# Copyright (C) 2016 D Levin (http://www.kfrlib.com)
# This file is part of KFR
#
# KFR is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# KFR is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with KFR.


cmake_minimum_required(VERSION 3.1)

message(STATUS CMAKE_CXX_FLAGS = ${CMAKE_CXX_FLAGS})

set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS}" CACHE STRING "compile flags" FORCE)

message(STATUS CMAKE_CXX_FLAGS = ${CMAKE_CXX_FLAGS})

project(kfr CXX)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)

message(STATUS "C++ compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} ${CMAKE_CXX_COMPILER} ")
message(STATUS CMAKE_SYSTEM_PROCESSOR = ${CMAKE_SYSTEM_PROCESSOR})

if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
    set (X86 TRUE)
else ()
    set (X86 FALSE)
endif ()

if (X86)
    message(STATUS X86)
endif ()

if (MSVC)
    message(STATUS MSVC)
endif()

if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
    set(CLANG 1)
else()
    set(CLANG 0)
endif()

# Include autogenerated list of source files
include(sources.cmake)

option(ENABLE_TESTS "Enable tests and examples" OFF)
if (CLANG)
    option(ENABLE_DFT "Enable DFT and related algorithms. Requires Clang" ON)
endif ()
option(ENABLE_ASMTEST "Enable writing disassembly" OFF)
option(REGENERATE_TESTS "Regenerate auto tests" OFF)
option(DISABLE_CLANG_EXTENSIONS "Disable Clang vector extensions" OFF)
option(KFR_EXTENDED_TESTS "Extended tests (up to hour)" OFF)
option(SKIP_TESTS "Skip tests (only build)" OFF)
mark_as_advanced(ENABLE_ASMTEST)
mark_as_advanced(REGENERATE_TESTS)
mark_as_advanced(DISABLE_CLANG_EXTENSIONS)

if (NOT CPU_ARCH)
    set(CPU_ARCH detect)
endif ()

if (CPU_ARCH STREQUAL "detect" AND X86)
    message(STATUS "Detecting native cpu...")
    try_run(
            RUN_RESULT COMPILE_RESULT
            "${CMAKE_CURRENT_BINARY_DIR}/tmpdir"
            ${CMAKE_CURRENT_SOURCE_DIR}/cmake/detect_cpu.cpp
            CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${CMAKE_CURRENT_SOURCE_DIR}/include" -DCMAKE_CXX_STANDARD=14
            -DCMAKE_CXX_STANDARD_REQUIRED=ON -DCMAKE_CXX_EXTENSIONS=ON
            COMPILE_OUTPUT_VARIABLE COMPILE_OUT
            RUN_OUTPUT_VARIABLE RUN_OUT
    )
    if (COMPILE_RESULT AND RUN_RESULT EQUAL 0)
        message(STATUS DETECTED_CPU = ${RUN_OUT})
        set(CPU_ARCH ${RUN_OUT} CACHE STRING "Detected CPU" FORCE)
    else()
        message(STATUS COMPILE_RESULT = ${COMPILE_RESULT})
        message(STATUS RUN_RESULT = ${RUN_RESULT})
        message(STATUS COMPILE_OUT = ${COMPILE_OUT})
        message(STATUS RUN_OUT = ${RUN_OUT})
    endif ()
endif ()

include(cmake/target_set_arch.cmake)

add_library(use_arch INTERFACE)
target_set_arch(use_arch INTERFACE ${CPU_ARCH})

if (WIN32)
    add_definitions(-D_CRT_SECURE_NO_WARNINGS)
    add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE)
endif()

if (IOS)
    set(STD_LIB)
else ()
    set(STD_LIB stdc++)
endif ()

if (ANDROID)
    set(PTHREAD_LIB)
else ()
    set(PTHREAD_LIB pthread)
endif ()

# KFR library
add_library(kfr INTERFACE)
target_sources(kfr INTERFACE ${KFR_SRC})
target_include_directories(kfr INTERFACE include)
target_compile_options(kfr INTERFACE "$<$<CONFIG:DEBUG>:-DKFR_DEBUG>")
if (NOT MSVC AND NOT IOS)
    target_compile_options(kfr INTERFACE -mstackrealign)
endif ()
if (MSVC)
    target_compile_options(kfr INTERFACE -bigobj)
else ()
    target_link_libraries(kfr INTERFACE ${STD_LIB} ${PTHREAD_LIB} m)
endif ()
if (DISABLE_CLANG_EXTENSIONS)
    target_compile_definitions(kfr INTERFACE -DCMT_DISABLE_CLANG_EXT)
endif ()
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    target_compile_options(kfr INTERFACE -Wno-ignored-qualifiers)
endif ()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    target_compile_options(kfr INTERFACE -Wno-c++1z-extensions)
endif ()

if (NOT ENABLE_DFT)
    target_compile_definitions(kfr INTERFACE -DKFR_NO_DFT)
endif ()
if (KFR_EXTENDED_TESTS)
    target_compile_definitions(kfr INTERFACE -DKFR_EXTENDED_TESTS)
endif()

message(STATUS CPU_ARCH=${CPU_ARCH})

if (ENABLE_TESTS)

    if (MSVC)
    else()
        # disable exceptions and rtti
        add_compile_options(-fno-exceptions -fno-rtti -fno-asynchronous-unwind-tables)
    endif ()

    add_subdirectory(examples)
    add_subdirectory(tests)
    add_subdirectory(tools)
endif ()

if (ENABLE_DFT)
    if (NOT CLANG)
        message(FATAL_ERROR "Clang compiler is required for DFT in KFR. See README.md for more information")
    endif()
    add_library(kfr_dft ${KFR_DFT_SRC})
    target_link_libraries(kfr_dft kfr use_arch)
    if (MSVC)
        target_compile_options(kfr_dft PRIVATE -fp:fast)
    else()
        target_compile_options(kfr_dft PRIVATE -ffast-math)
    endif()
endif()

add_library(kfr_io ${KFR_IO_SRC})
target_link_libraries(kfr_io kfr)
target_compile_definitions(kfr_io PUBLIC KFR_ENABLE_FLAC=1)

install(TARGETS kfr kfr_io ARCHIVE DESTINATION lib)

if (ENABLE_DFT)
    install(TARGETS kfr_dft ARCHIVE DESTINATION lib)
endif ()

install(DIRECTORY include/kfr DESTINATION include)
